// EnDecrypt.cpp : Defines the entry point for the DLL application.
//

#include "stdafx.h"
#include "../GYWA/Common/EnDecrypt.h"
#include "WinCrypt.h"
#include "TCHAR.H"
#include "malloc.h"

#define GY_AID_ENCRYPT_KEY			_T("GY_WALKING_AID_1.0")
#define GYWA_ENCRYPT				CALG_RC4

BOOL APIENTRY DllMain( HANDLE hModule, 
                       DWORD  ul_reason_for_call, 
                       LPVOID lpReserved
					 )
{
    switch (ul_reason_for_call)
	{
		case DLL_PROCESS_ATTACH:
		case DLL_THREAD_ATTACH:
		case DLL_THREAD_DETACH:
		case DLL_PROCESS_DETACH:
			break;
    }
    return TRUE;
}


ENDECRYPT_API BOOL EncryptString(TCHAR* szInString, TCHAR* szOutString)
{	
	BOOL bResult = TRUE;	
	HKEY hRegKey = NULL;	
	HCRYPTPROV hProv = NULL;	
	HCRYPTKEY hKey = NULL;
	HCRYPTKEY hXchgKey = NULL;	
	HCRYPTHASH hHash = NULL;	
	DWORD dwLength;
	// Get handle to user default provider.
	// Open first, if failed, new a set
	if (CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, 0)				||
		CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, CRYPT_NEWKEYSET)	)
	{
		// Create hash object.		
		if (CryptCreateHash(hProv, CALG_MD5, 0, 0, &hHash))		
		{
			// Hash password string.			
			dwLength = sizeof(TCHAR)*_tcslen(GY_AID_ENCRYPT_KEY);
			if (CryptHashData(hHash, (BYTE *)GY_AID_ENCRYPT_KEY, dwLength, 0))			
			{
				// Create block cipher session key based on hash of the password.
				if (CryptDeriveKey(hProv, GYWA_ENCRYPT, hHash, CRYPT_EXPORTABLE, &hKey))				
				{
					// Determine number of bytes to encrypt at a time.
					dwLength = sizeof(TCHAR)*_tcslen(szInString);					
					// Allocate memory.
					BYTE *pbBuffer = (BYTE *)malloc(dwLength);					
					if (pbBuffer != NULL)					
					{
						memcpy(pbBuffer, szInString, dwLength);						
						// Encrypt data
						if (CryptEncrypt(hKey, 0, TRUE, 0, pbBuffer, &dwLength, dwLength)) 						
						{
							// return encrypted string
							// memcpy(szEncryptPwd, pbBuffer, dwLength);
							// convert to ASCII char
							char* pCh = (char*)pbBuffer;
							for(DWORD i = 0; i < dwLength; i++)
							{
								int nCh = (pCh[i] & 0xF);
								*szOutString++ = (nCh < 10) ? ('0' + nCh) : ('A' + (nCh - 10));
								
								nCh = (pCh[i] & 0xF0) >> 4;
								*szOutString++ = (nCh < 10) ? ('0' + nCh) : ('A' + (nCh - 10));
							}
							
							*szOutString = 0;
						}	
						else						
						{							
							bResult = FALSE;						
						}						
						// Free memory
						free(pbBuffer);					
					}
					else					
					{						
						bResult = FALSE;					
					}
					CryptDestroyKey(hKey);  // Release provider handle.				
				}				
				else				
				{
					// Error during CryptDeriveKey!					
					bResult = FALSE;				
				}			
			}			
			else			
			{
				// Error during CryptHashData!				
				bResult = FALSE;			
			}
			CryptDestroyHash(hHash); 
			// Destroy session key.		
		}		
		else		
		{
			// Error during CryptCreateHash!			
			bResult = FALSE;		
		}
		CryptReleaseContext(hProv, 0);	
	}
	else
	{
		// Error during CryptAcquireContext!			
		bResult = FALSE;		
	}
	return bResult;
}

ENDECRYPT_API BOOL DecryptString(WCHAR* szInString, WCHAR* szOutString) 
{	
	BOOL bResult = TRUE;	
	HCRYPTPROV hProv = NULL;		
	HCRYPTKEY hKey = NULL;		
	HCRYPTKEY hXchgKey = NULL;
	HCRYPTHASH hHash = NULL;
	TCHAR szPasswordTemp[32] = _T("");
	DWORD dwLength;
	
	TCHAR szCopy[MAX_PATH] = {0};
	_tcscpy(szCopy, szInString);
	
	int nLen = _tcslen(szInString);
	memset(szInString, 0, sizeof(TCHAR) * nLen);
	
	unsigned char* pTmp = (unsigned char*)szInString;
	for(int i = 0; i < nLen; i += 2)
	{
		unsigned char ch = 0;
		int nCh = 0;
		
		if(szCopy[i+1] >= L'0' && szCopy[i+1] <= L'9')
			nCh = szCopy[i+1] - L'0';
		else
			nCh = 10 + szCopy[i+1] - L'A';
		
		ch = (nCh << 4);
		
		if(szCopy[i] >= L'0' && szCopy[i] <= L'9')
			nCh = szCopy[i] - L'0';
		else
			nCh = 10 + szCopy[i] - L'A';
		
		ch = (ch | nCh);
		
		pTmp[i/2] = ch; 
	}
	
	// Get handle to user default provider.
	if (CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, 0))		
	{
		// Create hash object.			
		if (CryptCreateHash(hProv, CALG_MD5, 0, 0, &hHash))
		{				
			// Hash password string.
			dwLength = sizeof(TCHAR)*_tcslen(GY_AID_ENCRYPT_KEY);
			if (CryptHashData(hHash, (BYTE *)GY_AID_ENCRYPT_KEY, dwLength, 0))				
			{
				// Create block cipher session key based on hash of the password.
				if (CryptDeriveKey(hProv, GYWA_ENCRYPT, hHash, CRYPT_EXPORTABLE, &hKey))					
				{
					// we know the encrypted password and the length
					dwLength = sizeof(TCHAR)*_tcslen(szInString);						
					// copy encrypted password to temporary TCHAR
					_tcscpy(szPasswordTemp,szInString);
					if (!CryptDecrypt(
						hKey, 0, TRUE, 0, (BYTE *)szPasswordTemp, &dwLength))
						bResult = FALSE;						
					CryptDestroyKey(hKey);  // Release provider handle.					
					// copy decrypted password to outparameter
					_tcscpy(szOutString,szPasswordTemp);
				}					
				else					
				{
					// Error during CryptDeriveKey!						
					bResult = FALSE;					
				}				
			}				
			else
			{					
				// Error during CryptHashData!					
				bResult = FALSE;				
			}
			CryptDestroyHash(hHash); // Destroy session key.			
		}			
		else			
		{
			// Error during CryptCreateHash!				
			bResult = FALSE;			
		}
		CryptReleaseContext(hProv, 0);		
	}
	else
	{
		DWORD dwError = GetLastError();
		if(dwError == NTE_BAD_KEYSET)
			int a= 1;

	}
	return bResult;
	
}
